/*
 * <h3>Title:wheel-spring-boot-web-starter系统</h3>
 * <p>Copyright (c) 2019, wnfbx@163.com. All rights reserved.</p>
 * @author wnfbx@163.com
 */
package com.wheel.core.result;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wheel.core.exception.GlobalAppException;
import com.wheel.core.exception.ResultCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.ui.ModelMap;
import org.springframework.validation.support.BindingAwareModelMap;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

@ApiModel("result")
public class Result<T> implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = -7583073716833020741L;

    // 返回值定义
    public static final String CODE_SUCCESS = "success";

    public static final String CODE_INFO = "info";

    // 返回值定义
    public static final String CODE_ERROR_LOCKED = "error_locked";

    public static final String CODE_ERROR_EXIST = "error_exist";

    public static final String CODE_ERROR_NOT_EXIST = "error_not_exist";

    public static final String CODE_ERROR_UNAUTHORIZED = "error_unauthorized";

    @ApiModelProperty("返回码(除了success，都是失败)")
    private String code;
    @ApiModelProperty("返回消息")
    private String message;
    @ApiModelProperty("返回数据")
    private T data;
    @ApiModelProperty("返回异常堆栈消息，开启系统调试后才会有内容")
    private String stackTrace;
    @ApiModelProperty("返回时间戳")
    private Date timestamp;
    @ApiModelProperty("请求ID")
    private String requestId;
    @ApiModelProperty("响应时间")
    private Long responseTime;

    public Long getResponseTime() {
        return responseTime;
    }

    public void setResponseTime(Long responseTime) {
        this.responseTime = responseTime;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getStackTrace() {
        return stackTrace;
    }

    public void setStackTrace(String stackTrace) {
        this.stackTrace = stackTrace;
    }

    public Date getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = new Date(timestamp);
    }

    public String getRequestId() {
        return requestId;
    }

    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }

    /**
     * <dt>Description:</dt>
     * <dd>创建输出model</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:27:13</i></dd>
     *
     * @param <T> 返回数据对象
     * @return {@link Result}
     */
    public static <T> Result<T> result() {
        return new Result<>();
    }

    /**
     * <dt>Description:</dt>
     * <dd>确定返回code及message</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:27:26</i></dd>
     *
     * @param result  传递结果
     * @param code    返回消息代码
     * @param message 返回消息
     * @return {@link Result}
     */
    public static <T> Result<T> result(Result<T> result, String code, String message) {
        if (result == null) {
            result = result();
        }
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    /**
     * <dt>Description:</dt>
     * <dd>成功结果</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:28:08</i></dd>
     *
     * @param result  传递结果
     * @param data    返回数据
     * @param message 返回消息
     * @return {@link Result}
     */
    public static <T> Result<T> success(Result<T> result, T data, String message) {
        result = result(result, Result.CODE_SUCCESS, message);
        result.setData(data);
        return result;
    }

    /**
     * <dt>Description:</dt>
     * <dd>成功结果</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:28:34</i></dd>
     *
     * @param data    返回数据
     * @param message 返回消息
     * @return {@link Result}
     */
    public static <T> Result<T> success(T data, String message) {
        return success(null, data, message);
    }

    /**
     * <dt>Description:</dt>
     * <dd>成功结果</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月5日 下午6:26:26</i></dd>
     *
     * @param data 返回数据
     * @return {@link Result}
     */
    public static <T> Result<T> success(T data) {
        return success(data, "");
    }

    /**
     * <dt>Description:</dt>
     * <dd>成功结果</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:29:00</i></dd>
     *
     * @return {@link Result}
     */
    public static <T> Result<T> success() {
        return success(null);
    }

    /**
     * <dt>Description:</dt>
     * <dd>失败但是程序可以继续运行</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:29:10</i></dd>
     *
     * @param result  传递结果
     * @param data    返回数据
     * @param message 返回消息
     * @return {@link Result}
     */
    public static <T> Result<T> info(Result<T> result, T data, String message) {
        if (result != null) {
            String o = result.getMessage();
            message = message + (o == null ? "" : o);
        }
        result = result(result, Result.CODE_INFO, message);
        result.setData(data);
        return result;
    }

    /**
     * <dt>Description:</dt>
     * <dd>失败但是程序可以继续运行</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:29:38</i></dd>
     *
     * @param data    返回数据
     * @param message 返回消息
     * @return {@link Result}
     */
    public static <T> Result<T> info(T data, String message) {
        return info(null, data, message);
    }

    /**
     * <dt>Description:error</dt>
     * <dd>不能正确返回或返回正确的结果</dd>
     * <dd>author: wangnaifei@163.com</dd>
     * <dd>version:1.0 <i>2019/12/11 19:22</i></dd>
     *
     * @param result            传递结果
     * @param code              返回消息代码
     * @param message           返回消息
     * @param stackTraceMessage 异常消息
     * @return {@link Result}
     * @since jdk1.7+
     */
    public static <T> Result<T> error(Result<T> result, String code, String message, String stackTraceMessage) {
        result = result(result, code, message);
        result.setStackTrace(stackTraceMessage);
        return result;
    }

    /**
     * <dt>Description:</dt>
     * <dd>不能正确返回或返回正确的结果</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午7:31:53</i></dd>
     *
     * @param code              返回消息代码
     * @param message           返回消息
     * @param stackTraceMessage 异常消息
     * @return {@link Result}
     */
    public static <T> Result<T> error(String code, String message, String stackTraceMessage) {
        return error(null, code, message, stackTraceMessage);
    }

    /**
     * <dt>Description:error</dt>
     * <dd>返回异常结果</dd>
     * <dd>author: wangnaifei@163.com</dd>
     * <dd>version:1.0 <i>2019/12/11 16:45</i></dd>
     *
     * @param result    传递结果
     * @param code      返回消息代码
     * @param message   返回消息
     * @param throwable 异常
     * @return {@link Result}
     * @since jdk1.7+
     */
    public static <T> Result<T> error(Result<T> result, String code, String message, Throwable throwable) {
        return error(result, code, message, GlobalAppException.getPrintStackTraceMessage(throwable));
    }

    /**
     * <dt>Description:error</dt>
     * <dd>返回异常结果</dd>
     * <dd>author: wangnaifei@163.com</dd>
     * <dd>version:1.0 <i>2019/12/11 16:44</i></dd>
     *
     * @param code      异常消息代码
     * @param message   异常消息内容
     * @param throwable 异常
     * @return {@link Result}
     * @since jdk1.7+
     */
    public static <T> Result<T> error(String code, String message, Throwable throwable) {
        return error(null, code, message, throwable);
    }

    public static ResultCode newCode(String code) {
        return new ResultCode(code);
    }

    public ModelMap toModel() {
        BindingAwareModelMap bindingAwareModelMap = new BindingAwareModelMap();
        Method[] declaredMethods = this.getClass().getDeclaredMethods();
        for (Method method : declaredMethods) {
            String name = method.getName();
            if (name.startsWith("get")) {
                name = name.substring(3);
                name = name.substring(0, 1).toLowerCase() + name.substring(1);
                try {
                    bindingAwareModelMap.put(name, method.invoke(this));
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return bindingAwareModelMap;
    }

    public Result<JSONObject> putData(String key, Object value) {
        if (this.data == null) {
            this.setData((T) new JSONObject());
        } else if (this.data != null && this.data instanceof JSONObject) {
            ((JSONObject) this.data).put(key, value);
        } else {
            throw new RuntimeException("data is null or data is not JSONObject");
        }
        return (Result<JSONObject>) this;
    }

    @ApiModelProperty("是否成功返回")
    public boolean isSuccess() {
        return CODE_SUCCESS.equals(this.code);
    }
}
